using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Acms.Bll;

namespace Acms.AcmsControls
{
    interface IContentControlLoader
    {
        void LoadData(AcmsContext context, Acms.Bll.PostControl postControl);
        void LoadData(AcmsContext context, Acms.Bll.UnusedPostControl postControl);
    }

    public abstract class BaseContentControlDisplay<T> : CompositeControl, IContentControlLoader where T : BaseContentControlProperties, new()
    {
        //protected abstract BaseContentControlProperties GetProperties();
        //protected abstract void SetProperties(BaseContentControlProperties properties);

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
        }

        protected T Properties{get;private set;}

        private void LoadData(System.Xml.XmlDocument xmlDocument)
        {
            if (xmlDocument != null)
            {

                System.Xml.Serialization.XmlSerializer xmls = new System.Xml.Serialization.XmlSerializer(typeof(T));

                try
                {
                    Properties = (T)xmls.Deserialize(new System.IO.StringReader(xmlDocument.OuterXml));
                }
                catch
                {
                    T tmp = new T();
                    tmp.ReadXml(System.Xml.XmlReader.Create(new System.IO.StringReader(xmlDocument.OuterXml)));
                    Properties = tmp;
                }
                PropertiesLoaded(Properties);
            }
        }

        public virtual void PropertiesLoaded(T properties)
        {
        }

        public void LoadData(AcmsContext context, Acms.Bll.PostControl postControl)
        {
            try
            {
                LoadData(postControl.Value);
            }
            catch(System.Xml.XmlException e)
            {
                throw new Acms.Exceptions.ContentControlException(string.Format("Failed to load Xml Data for PostControlId '{0}' : {1}", postControl.Id, e.Message));
            }
        }

        public void LoadData(AcmsContext context, Acms.Bll.UnusedPostControl postControl)
        {
            CurrentContext = context;
            try
            {
                LoadData(postControl.Value);
            }
            catch (System.Xml.XmlException e)
            {
                throw new Acms.Exceptions.ContentControlException(string.Format("Failed to load Xml Data for PostControlId '{0}' : {1}", postControl.Id, e.Message));
            }

        }

        private string controlName;
        public string ControlName
        {
            get { return controlName; }
            set { controlName = value; }
        }

        protected Post FindCurrentPost()
        {
            var post = FindCurrentPost(this.NamingContainer);
            if (post == null && this.Page is TemplatePage)
            {
                return ((TemplatePage)this.Page).AcmsContext.CurrentPost;
            }
            else
            {
                return post;
            }
        }

        private Post FindCurrentPost(Control ctrl)
        {
            if (ctrl is IDataItemContainer && ((System.Web.UI.IDataItemContainer)ctrl).DataItem is Post)
            {
                var post = (Post)((IDataItemContainer)ctrl).DataItem;
                if (post is DummyPost)
                    return null;
                else
                    return post;
            }
            else if (ctrl is Acms.AcmsControls.TemplateUserControl)
            {
                return ((Acms.AcmsControls.TemplateUserControl)ctrl).AcmsContext.CurrentPost;
            }
            else if (ctrl.NamingContainer != null)
            {
                return FindCurrentPost(ctrl.NamingContainer);
            }
            else
            {
                return null;
            }
        }


        public sealed override void DataBind()
        {
            Acms.Bll.PostControl postControl = null;
            TemplateUserControl template = FindTemplateControl(this.NamingContainer);
            Post currentPost = FindCurrentPost();
            //find containg BaseTemplateControl
            //else not there find page

            if (template != null)
            {
                CurrentContext = template.AcmsContext;
            }
            else if (this.Page is TemplatePage)
            {
                CurrentContext = ((TemplatePage)Page).AcmsContext;
            }
            else
            {
                throw new ApplicationException("Could not find Template. All Content Controls must be exists in a Template which inherits from BaseTemplateControl");
            }

            if (currentPost != null)
            {
                postControl = currentPost.FindPostControl(this.ControlName);
            }
            else
            {
                SetDevProperties();
            }

            if (postControl != null)
            {
                LoadData(CurrentContext, postControl);
            }
            EnsureChildControls();
            DataBindChildren();
            requiresDataBinding = false;
            OnDataBound(EventArgs.Empty);
        }

        protected void OnDataBound(EventArgs e)
        {
            if (DataBound != null)
            {
                DataBound(this, e);
            }
        }

        public event EventHandler DataBound;

        private TemplateUserControl FindTemplateControl(Control control)
        {
            if(control == null)
            {
                return null;
            }
            else if (control is TemplateUserControl)
            {
                return control as TemplateUserControl;
            }
            else
            {
                return FindTemplateControl(control.NamingContainer);
            }
        }


        bool requiresDataBinding = true;
        public void SetRequiresDatabinding()
        {
            requiresDataBinding = true;
        }

        protected override object SaveViewState()
        {
            ViewState["requiresDataBinding"] = requiresDataBinding;
            return base.SaveViewState();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
            if(ViewState["requiresDataBinding"] is bool)
                requiresDataBinding = (bool)ViewState["requiresDataBinding"];
        }

        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (requiresDataBinding)
                DataBind();
        }

        protected AcmsContext CurrentContext;

        public abstract bool IsEmpty { get; }

        public virtual void SetDevProperties()
        {
        }
    }
}
